package com.wimcorp.magic.phase;

import java.rmi.RemoteException;
import java.util.HashSet;
import java.util.Set;

import javax.transaction.SystemException;

import com.wimcorp.magic.abilities.Ability;
import com.wimcorp.magic.cards.Creature;
import com.wimcorp.magic.cards.Instant;
import com.wimcorp.magic.cards.Land;
import com.wimcorp.magic.cards.PlayingCard;
import com.wimcorp.magic.exception.CostException;
import com.wimcorp.magic.input.Location;
import com.wimcorp.magic.input.Target;
import com.wimcorp.magic.input.Type;
import com.wimcorp.magic.players.Player;
import com.wimcorp.magic.spell.Castable;

public class MainPhase extends Phase {

	private Set<Ability> mainPhaseObservers = new HashSet<Ability>();

	public MainPhase(Player activePlayer) {
		super(activePlayer);
	}

	public void execute() {

		begin();
		if (getStack().size() != 0) {
			activateAbilities();
		}
		playCards();
		activateAbilities();
	}

	private void begin() {

		if (!Turn.isSecondMainPhase()) {
			messagePlayer("Main phase. ");
			messageOpponent(String.format("Opponent (%s) main phase. ",getActivePlayer().getName()));
		} else {
			messagePlayer("Second main phase. ");
			messageOpponent(String.format("Opponent (%s) second main phase. ",getActivePlayer().getName()));
		}

		// trigger abilities at beginning of main phase
		for (Ability mainPhaseObserver : mainPhaseObservers) {
			getActivePlayer().cast(mainPhaseObserver);
		}
		if (getStack().size() != 0) {
			// resolve stack
			getStack().resolve();
		}

	}

	private void playCards() {
		try {
			long cardId = -1;
			do {
				try {
					cardId = getActivePlayerUserInterface().select(Target.SELF, Type.CARD, Location.HAND);
					PlayingCard card = getActivePlayer().getHand().getCard(cardId);
					if (card != null) {
						if (card instanceof Land && !Turn.hasPlayedLand()) {
							boolean succes = getActivePlayer().castLand(card);
							if (succes) {
								Turn.setPlayedLand(succes);
								messagePlayer(String.format("You played %s. ", card.getName()));
								messageOpponent(String.format("Opponent %s played %s. ", getActivePlayer().getName(),
										card.getName()));
							}
						} else if (card instanceof Land && Turn.hasPlayedLand()) {
							throw new SystemException("You already played a land this turn. ");
						} else {
							getActivePlayer().cast(card);
							
							//((Creature)card).add
							String counterMessage = String.format("Would you like to counter %s? ",
									card.getCastDescription());
							boolean counterSpell = getActivePlayer().getOpponent().getUserInterface()
									.selectBoolean(counterMessage);
							if (counterSpell) {
								messagePlayer(String.format("Opponent wants to counter %s. ", card.getName()));
								setActivePlayer(getActivePlayer().getOpponent());
								counter();
								setActivePlayer(getActivePlayer().getOpponent());
							} else {
								messagePlayer(String.format("Opponent does not counter %s. ", card.getName()));
							}
							getStack().resolve();
						}
					}
				} catch (SystemException | CostException e) {
					getActivePlayerUserInterface().message(e.getMessage());
				}
			} while (cardId != -1);
		} catch (RemoteException e) {
			e.printStackTrace();
		}
		// cast artifact, creature, enchantment, planeswalker, and sorcery
		// spells.
	}

	private void counter() {
		try {
			long cardId = -1;
			do {
				try {
					cardId = getActivePlayerUserInterface().select(Target.SELF, Type.CARD, Location.HAND);
					PlayingCard card = getActivePlayer().getHand().getCard(cardId);
					if (card != null) {
						if (card instanceof Instant /*|| card.hasBehaviour(Flash.instance)*/) {
							getActivePlayer().cast(card);
							messagePlayer(String.format("You played %s. ", card.getName()));
							messageOpponent(String.format("Opponent %s played %s", getActivePlayer().getOpponent()
									.getName(), card.getName()));
							boolean counterSpell = getActivePlayer().getOpponent().getUserInterface()
									.selectBoolean(String.format("Would you like to counter %s?", card.getName()));
							if (counterSpell) {
								setActivePlayer(getActivePlayer().getOpponent());
								counter();
								setActivePlayer(getActivePlayer().getOpponent());
							}
						} else {
							// TODO abilities??
							getActivePlayerUserInterface().message("You can only counter a spell with an Instant.");
						}
					}
				} catch (CostException e) {
					getActivePlayerUserInterface().message(e.getMessage());
				}

			} while (cardId != -1);
		} catch (RemoteException e) {
			e.printStackTrace();
		}
		// cast artifact, creature, enchantment, planeswalker, and sorcery
		// spells.
	}

	public void registerMainPhaseObserver(Ability ability) {
		mainPhaseObservers.add(ability);
	}

	public void unRegisterMainPhaseObserver(Ability ability) {
		mainPhaseObservers.remove(ability);
	}

}
